﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Net.Sockets;
using OscarClover.Exception;
using OscarClover.Packets.SignOff;
using OscarClover.Packets.SignOn;
using OscarClover.Packets.SnacData;

namespace OscarClover
{
    public class Session
    {
        private readonly OscarFormatter _formatter = new OscarFormatter();

        private List<byte[]> CurrentCapabilities { get; set; }

        #region Client Properties
        private const String ClientId = "CloverIM";

        private const ushort MajorVersion = 6;

        private const ushort MinorVersion = 5;

        private const ushort LesserVersion = 0;

        private const ushort BuildNumber = 1042;

        private const ushort ClientIdNumber = 266;

        private const ushort ClientDistributionNumber = 0;

        private const String ClientLanguage = "ru";

        private const String ClientCountry = "ru";
        #endregion
        
        private static ushort _sequence;

        public static ushort Sequence
        {
            get
            {
                return _sequence;
            }
            set
            {
                if (value<=32768)
                {
                    _sequence = value;
                }
                else
                {
                    _sequence = 0;
                }
            }
        }

        public static ushort RecievedSequence { get; set; }

        private String host;

        private Byte[] autorizationCookie;

        private TcpClient _client;

        private NetworkStream n;

        public Session()
        {
            CurrentCapabilities = new List<byte[]> {Capabilities.AimIcq, Capabilities.ServerRelaying, Capabilities.Utf8};
        }

        public void Login(String uin, String pass)
        {
            
            try
            {
                host = "login.icq.com";
                _client = new TcpClient(host, 5190);
                Sequence = (ushort)new Random().Next(32768);
                n = _client.GetStream();
                _formatter.Deserialize(n);
                var cliSignOn = new CliSignOn(uin, pass, ClientId, MajorVersion, MinorVersion, LesserVersion, BuildNumber, ClientIdNumber, ClientDistributionNumber, ClientLanguage, ClientCountry);
                _formatter.Serialize(n, cliSignOn);


                var srvReply = _formatter.Deserialize(n);
                if (srvReply is SrvCookie)
                {
                    _formatter.Serialize(n, new CloseConnection());
                    n.Close();
                    _client.Close();
                    host = (srvReply as SrvCookie).Bos.Substring(0, (srvReply as SrvCookie).Bos.IndexOf(":"));
                    _client = new TcpClient(host, 5190);
                    n = _client.GetStream();
                    autorizationCookie = (srvReply as SrvCookie).AutorizationCookie;
                    var replying = new Thread(Replying);
                    replying.Start();
                    Thread.Sleep(5000);
                }

                /*var srvCookie = srvReply as SrvCookie;
                _formatter.Serialize(n, new CloseConnection());
                n.Close();
                _client.Close();
                host = srvCookie.Bos.Substring(0, srvCookie.Bos.IndexOf(":"));
                _client = new TcpClient(host, 5190);
                n = _client.GetStream();
                _formatter.Deserialize(n);
                cliSignOn = new CliSignOn(srvCookie.AutorizationCookie);
                _formatter.Serialize(n, cliSignOn);
                var srvFamilies = _formatter.Deserialize(n) as SrvFamilies;
                _formatter.Deserialize(n); //SrvWellKnowUrl
                var cliFamiliesVersions = new CliFamiliesVersions(srvFamilies.Services);
                _formatter.Serialize(n, cliFamiliesVersions);
                var srvFamiliesVersions = _formatter.Deserialize(n) as SrvFamiliesVersions;
                _formatter.Deserialize(n); //SrvMOTD
                _formatter.Serialize(n,new CliRequest(0x01,0x06));
                var srvRateLimitInfo = _formatter.Deserialize(n) as SrvRateLimitInfo;
                _formatter.Serialize(n,new CliRatesAck(srvRateLimitInfo.ClassCount));
                _formatter.Cache(new CliRequest(0x01,0x0E));
                _formatter.Cache(new CliRequest(0x02, 0x02));
                _formatter.Cache(new CliRequest(0x03, 0x02));
                _formatter.Cache(new CliRequest(0x04, 0x04));
                _formatter.Cache(new CliRequest(0x09, 0x02));
                _formatter.Cache(new CliRequest(0x13, 0x02));
                _formatter.Cache(new CliRequest(0x13, 0x04));
                _formatter.FlushCache(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Deserialize(n);
                _formatter.Serialize(n,new CliSetLocationInfo(CurrentCapabilities));
                _formatter.Serialize(n, new CliSetStatus(Flags.DcAuth,Status.Online));
                _formatter.Serialize(n,new CliReady(srvFamiliesVersions.Families,1000));
                _formatter.Serialize(n,new CliRequest(0x013,0x07));
                 */
            }
            catch (DeserializeException e)
            {
                Console.WriteLine(e.Message);
            }           
        }

        private void Replying()
        {
            Dictionary<byte,byte> servicesVersion = null;
            while (true)
            {
                var srvReply = _formatter.Deserialize(n);
                if (srvReply is Connect)
                {
                    _formatter.Serialize(n,new CliSignOn(autorizationCookie));
                } 
                else if (srvReply is SrvFamilies)
                {
                    _formatter.Serialize(n, new CliFamiliesVersions((srvReply as SrvFamilies).Services));
                }
                else if (srvReply is SrvFamiliesVersions)
                {
                    servicesVersion = (srvReply as SrvFamiliesVersions).Families;
                    _formatter.Serialize(n, new CliRequest(0x01, 0x06));
                }
                else if (srvReply is SrvRateLimitInfo)
                {
                    _formatter.Serialize(n, new CliRatesAck((srvReply as SrvRateLimitInfo).ClassCount));
                    _formatter.Cache(new CliRequest(0x01, 0x0E));
                    _formatter.Cache(new CliRequest(0x02, 0x02));
                    _formatter.Cache(new CliRequest(0x03, 0x02));
                    _formatter.Cache(new CliRequest(0x04, 0x04));
                    _formatter.Cache(new CliRequest(0x09, 0x02));
                    _formatter.Cache(new CliRequest(0x13, 0x02));
                    _formatter.Cache(new CliRequest(0x13, 0x04));
                    _formatter.FlushCache(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Deserialize(n);
                    _formatter.Serialize(n, new CliSetLocationInfo(CurrentCapabilities));
                    _formatter.Serialize(n, new CliSetStatus(Flags.DcAuth, Status.Online));
                    _formatter.Serialize(n, new CliReady(servicesVersion, 1000));
                    _formatter.Serialize(n, new CliRequest(0x013, 0x07));
                }
            }
        }
    }
}